Merge Generator

The Merge generator combines parameters produced by the base (first) generator with matching parameter sets produced by subsequent generators. A matching parameter set has the same values for the configured merge keys. Non-matching parameter sets are discarded. Override precedence is bottom-to-top: the values from a matching parameter set produced by generator 3 will take precedence over the values from the corresponding parameter set produced by generator 2.

Using a Merge generator is appropriate when a subset of parameter sets require overriding.

Example: Base Cluster generator + override Cluster generator + List generator

As an example, imagine that we have two clusters:

  • A staging cluster (at https://1.2.3.4)
  • A production cluster (at https://2.4.6.8)
  1. apiVersion: argoproj.io/v1alpha1
  2. kind: ApplicationSet
  3. metadata:
  4. name: cluster-git
  5. spec:
  6. generators:
  7. # merge 'parent' generator
  8. - merge:
  9. mergeKeys:
  10. - server
  11. generators:
  12. - clusters:
  13. values:
  14. kafka: 'true'
  15. redis: 'false'
  16. # For clusters with a specific label, enable Kafka.
  17. - clusters:
  18. selector:
  19. matchLabels:
  20. use-kafka: 'false'
  21. values:
  22. kafka: 'false'
  23. # For a specific cluster, enable Redis.
  24. - list:
  25. elements:
  26. - server: https://2.4.6.8
  27. values.redis: 'true'
  28. template:
  29. metadata:
  30. name: '{{name}}'
  31. spec:
  32. project: '{{metadata.labels.environment}}'
  33. source:
  34. repoURL: https://github.com/argoproj/argo-cd.git
  35. targetRevision: HEAD
  36. path: app
  37. helm:
  38. parameters:
  39. - name: kafka
  40. value: '{{values.kafka}}'
  41. - name: redis
  42. value: '{{values.redis}}'
  43. destination:
  44. server: '{{server}}'
  45. namespace: default

The base Cluster generator scans the set of clusters defined in Argo CD, finds the staging and production cluster secrets, and produces two corresponding sets of parameters:

  1. - name: staging
  2. server: https://1.2.3.4
  3. values.kafka: 'true'
  4. values.redis: 'false'
  5. - name: production
  6. server: https://2.4.6.8
  7. values.kafka: 'true'
  8. values.redis: 'false'

The override Cluster generator scans the set of clusters defined in Argo CD, finds the staging cluster secret (which has the required label), and produces the following parameters:

  1. - name: staging
  2. server: https://1.2.3.4
  3. values.kafka: 'false'

When merged with the base generator’s parameters, the values.kafka value for the staging cluster is set to 'false'.

  1. - name: staging
  2. server: https://1.2.3.4
  3. values.kafka: 'false'
  4. values.redis: 'false'
  5. - name: production
  6. server: https://2.4.6.8
  7. values.kafka: 'true'
  8. values.redis: 'false'

Finally, the List cluster generates a single set of parameters:

  1. - server: https://2.4.6.8
  2. values.redis: 'true'

When merged with the updated base parameters, the values.redis value for the production cluster is set to 'true'. This is the merge generator’s final output:

  1. - name: staging
  2. server: https://1.2.3.4
  3. values.kafka: 'false'
  4. values.redis: 'false'
  5. - name: production
  6. server: https://2.4.6.8
  7. values.kafka: 'true'
  8. values.redis: 'true'

Example: Use value interpolation in merge

Some generators support additional values and interpolating from generated variables to selected values. This can be used to teach the merge generator which generated variables to use to combine different generators.

The following example combines discovered clusters and a git repository by cluster labels and the branch name:

  1. apiVersion: argoproj.io/v1alpha1
  2. kind: ApplicationSet
  3. metadata:
  4. name: cluster-git
  5. spec:
  6. generators:
  7. # merge 'parent' generator:
  8. # Use the selector set by both child generators to combine them.
  9. - merge:
  10. mergeKeys:
  11. # Note that this would not work with goTemplate enabled,
  12. # nested merge keys are not supported there.
  13. - values.selector
  14. generators:
  15. # Assuming, all configured clusters have a label for their location:
  16. # Set the selector to this location.
  17. - clusters:
  18. values:
  19. selector: '{{ metadata.labels.location }}'
  20. # The git repo may have different directories which correspond to the
  21. # cluster locations, using these as a selector.
  22. - git:
  23. repoURL: https://github.com/argoproj/argocd-example-apps/
  24. revision: HEAD
  25. directories:
  26. - path: '*'
  27. values:
  28. selector: '{{ path }}'
  29. template:
  30. metadata:
  31. name: '{{name}}'
  32. spec:
  33. project: '{{metadata.labels.environment}}'
  34. source:
  35. repoURL: https://github.com/argoproj/argocd-example-apps/
  36. # The cluster values field for each generator will be substituted here:
  37. targetRevision: HEAD
  38. path: '{{path}}'
  39. destination:
  40. server: '{{server}}'
  41. namespace: default

Assuming a cluster named germany01 with the label metadata.labels.location=Germany and a git repository containing a directory called Germany, this could combine to values as follows:

  1. # From the cluster generator
  2. - name: germany01
  3. server: https://1.2.3.4
  4. # From the git generator
  5. path: Germany
  6. # Combining selector with the merge generator
  7. values.selector: 'Germany'
  8. # More values from cluster & git generator
  9. # […]

Restrictions

  1. You should specify only a single generator per array entry. This is not valid:

    1. - merge:
    2. generators:
    3. - list: # (...)
    4. git: # (...)
    • While this will be accepted by Kubernetes API validation, the controller will report an error on generation. Each generator should be specified in a separate array element, as in the examples above.
  2. The Merge generator does not support template overrides specified on child generators. This template will not be processed:

    1. - merge:
    2. generators:
    3. - list:
    4. elements:
    5. - # (...)
    6. template: { } # Not processed
  3. Combination-type generators (Matrix or Merge) can only be nested once. For example, this will not work:

    1. - merge:
    2. generators:
    3. - merge:
    4. generators:
    5. - merge: # This third level is invalid.
    6. generators:
    7. - list:
    8. elements:
    9. - # (...)
  4. Merging on nested values while using goTemplate: true is currently not supported, this will not work

    1. spec:
    2. goTemplate: true
    3. generators:
    4. - merge:
    5. mergeKeys:
    6. - values.merge
  5. When using a Merge generator nested inside another Matrix or Merge generator, Post Selectors for this nested generator’s generators will only be applied when enabled via spec.applyNestedSelectors.

    1. - merge:
    2. generators:
    3. - merge:
    4. generators:
    5. - list
    6. elements:
    7. - # (...)
    8. selector: { } # Only applied when applyNestedSelectors is true